package com.ruoyi.quartz.task;

import com.google.common.util.concurrent.*;
import com.ruoyi.bizsys.domain.SmsTask;
import com.ruoyi.bizsys.domain.SmsTemplate;
import com.ruoyi.bizsys.service.ISmsTaskService;
import com.ruoyi.bizsys.service.ISmsTemplateService;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.Func;
import com.ruoyi.quartz.mapper.QuartzSmsMapper;
import com.ruoyi.quartz.thread.SmsTaskThread;
import com.ruoyi.sms.service.ISmsService;
import com.ruoyi.system.service.ISysConfigService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 短信发送任务
 *
 * @author ruoyi
 */
@Slf4j
@AllArgsConstructor
@Component("smsSendTask")
public class SmsSendTask {

    private ISmsTaskService smsTaskService;

    private ISmsService smsService;

    private QuartzSmsMapper quartzSmsMapper;

    private ISmsTemplateService smsTemplateService;

    private ISysConfigService iSysConfigService;

    private RedisCache redisCache;

    public void execute() {

        log.info("短信发送任务 Start >>>>>>>>>>");

        //只发送当前时刻的短信模版
        String oClock = DateUtils.getCurrentClock();
        log.info("当前时刻：{}", oClock);
        List<String> smsTypes = new ArrayList<>();
        SmsTemplate smsTemplate = new SmsTemplate();
        smsTemplate.setState("1");
        List<SmsTemplate> smsTemplates = smsTemplateService.selectSmsTemplateList(smsTemplate);
        smsTemplates.forEach(e -> {
            //单个模版可以选择多时刻发送，空则默认全天
            if (Func.isNotEmpty(e.getSendClock())) {
                String[] times = e.getSendClock().split(",");
                if (Arrays.asList(times).contains(oClock)) {
                    smsTypes.add(e.getSmsType());
                }
            } else {
                smsTypes.add(e.getSmsType());
            }
        });

        //区分普通短信和定期短信
        List<SmsTask> smsTaskList = quartzSmsMapper.getSmsTaskInType(smsTypes);
        log.info("待处理短信任务记录数：{}", smsTaskList.size());

        int smsTaskListSize = smsTaskList.size();
        if (smsTaskListSize > 0) {
            Date date = new Date();
            String redisName = "SmsSendTask-" + DateUtils.dateTime(date);

            String smsSendTaskConfig = iSysConfigService.selectConfigByKey("sms_send_task_config");

            String[] split = smsSendTaskConfig.split(",");


            int threadStep = Integer.parseInt(split[0]);//每个线程执行的客户数
            //需要multiple个线程来执行
            int threadCount = smsTaskListSize / threadStep;
            if (threadCount * threadStep != smsTaskListSize) {
                threadCount++;
            }
            //线程计数器
            final CountDownLatch countDownLatch = new CountDownLatch(threadCount);
            //线程池大小
            int poolSize = Integer.parseInt(split[1]);

            ExecutorService executorService = Executors.newFixedThreadPool(poolSize);
            ListeningExecutorService listeningExecutorService = MoreExecutors.listeningDecorator(executorService);

            int threadAccountCount = 0;
            while (threadAccountCount != smsTaskListSize) {
                //分页取数startNum
                int startLimit = threadAccountCount;

                threadAccountCount += threadStep;

                if (threadAccountCount > smsTaskListSize) {
                    threadAccountCount = smsTaskListSize;
                }

                String redisName1 = redisName + ":" + startLimit + "-" + threadAccountCount;
                List<SmsTask> smsTaskList1 = smsTaskList.subList(startLimit, threadAccountCount);
                redisCache.setCacheList(redisName1, smsTaskList1);
                redisCache.expire(redisName1, 23, TimeUnit.HOURS);

                SmsTaskThread thread = new SmsTaskThread("[SmsTaskThread-" + startLimit + "]", redisName1,
                        smsService, quartzSmsMapper, smsTaskService, redisCache);
                ListenableFuture listenableFuture = listeningExecutorService.submit(thread);

                Futures.addCallback(listenableFuture, new FutureCallback<String>() {
                    @Override
                    public void onSuccess(String result) {
                        countDownLatch.countDown();
                        log.info("[" + this.getClass().getName() + "]线程处理结果：" + result);
                    }

                    @Override
                    public void onFailure(Throwable throwable) {
                        countDownLatch.countDown();
                        log.info("[" + this.getClass().getName() + "]线程处理出错：" + throwable);
                    }
                });
            }

            try {
                countDownLatch.await(3 * 60, TimeUnit.MINUTES);//超过3个小时放弃
            } catch (InterruptedException e) {
                log.error("当日跑批执行失败，非正常结束", e);
            }
        }

        log.info("短信发送任务 End >>>>>>>>>>");
    }

}
